<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace core\http\bags;

use core\http\GetSettable;

/**
 * ParameterBag is a container for key/value pairs.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ParameterBag implements GetSettable{
	protected $parameters;
	
	/**
	 * Constructor.
	 *
	 * @param array $parameters An array of parameters
	 */
	public function __construct(array $parameters = array()) {
		$this->parameters = $parameters;
	}
	
	/**
	 * Returns the parameters.
	 *
	 * @return array An array of parameters
	 */
	public function all() {
		return $this->parameters;
	}
	
	/**
	 * Returns the parameter keys.
	 *
	 * @return array An array of parameter keys
	 */
	public function keys() {
		return array_keys( $this->parameters );
	}
	
	/**
	 * Replaces the current parameters by a new set.
	 *
	 * @param array $parameters An array of parameters
	 */
	public function replace(array $parameters = array()) {
		$this->parameters = $parameters;
	}
	
	/**
	 * Adds parameters.
	 *
	 * @param array $parameters An array of parameters
	 */
	public function add(array $parameters = array()) {
		$this->parameters = array_replace( $this->parameters, $parameters );
	}
	
	/**
	 * Returns a parameter by name.
	 *
	 * @param string $key     The key
	 * @param mixed  $default The default value
	 */
	public function get($key, $default = null) {
		return array_key_exists( $key, $this->parameters ) ? $this->parameters[$key] : $default;
	}
	
	/**
	 * Returns a parameter by name allowing to specify a path with arbitrary depth.
	 *
	 * @param string $path   The path, e.g. foo[bar]
	 * @param mixed $default The default value
	 */
	public function getDeep($path, $default = null) {
		if( false === $pos = strpos( $path, '[' ) ) {
			return $this->get( $path, $default );
		}
		
		$root = substr( $path, 0, $pos );
		if( !array_key_exists( $root, $this->parameters ) ) {
			return $default;
		}
		
		$value = $this->parameters[$root];
		$currentKey = null;
		for( $i = $pos, $c = strlen( $path ); $i < $c; $i++ ) {
			$char = $path[$i];
			
			if( '[' === $char ) {
				if( null !== $currentKey ) {
					throw new \InvalidArgumentException( sprintf( 'Malformed path. Unexpected "[" at position %d.', $i ) );
				}
				
				$currentKey = '';
			} else if( ']' === $char ) {
				if( null === $currentKey ) {
					throw new \InvalidArgumentException( sprintf( 'Malformed path. Unexpected "]" at position %d.', $i ) );
				}
				
				if( !is_array( $value ) || !array_key_exists( $currentKey, $value ) ) {
					return $default;
				}
				
				$value = $value[$currentKey];
				$currentKey = null;
			} else {
				if( null === $currentKey ) {
					throw new \InvalidArgumentException( sprintf( 'Malformed path. Unexpected "%s" at position %d.', $char, $i ) );
				}
				
				$currentKey .= $char;
			}
		}
		
		if( null !== $currentKey ) {
			throw new \InvalidArgumentException( sprintf( 'Malformed path. Path must end with "]".' ) );
		}
		
		return $value;
	}
	
	/**
	 * Sets a parameter by name.
	 *
	 * @param string $key   The key
	 * @param mixed  $value The value
	 */
	public function set($key, $value) {
		$this->parameters[$key] = $value;
	}
	
	/**
	 * Returns true if the parameter is defined.
	 *
	 * @param string $key The key
	 *
	 * @return Boolean true if the parameter exists, false otherwise
	 */
	public function has($key) {
		return array_key_exists( $key, $this->parameters );
	}
	
	/**
	 * Removes a parameter.
	 *
	 * @param string $key The key
	 */
	public function remove($key) {
		unset( $this->parameters[$key] );
	}
	
	/**
	 * Returns the alphabetic characters of the parameter value.
	 *
	 * @param string $key     The parameter key
	 * @param mixed  $default The default value
	 *
	 * @return string The filtered value
	 */
	public function getAlpha($key, $default = '') {
		return preg_replace( '/[^[:alpha:]]/', '', $this->get( $key, $default ) );
	}
	
	/**
	 * Returns the alphabetic characters and digits of the parameter value.
	 *
	 * @param string $key     The parameter key
	 * @param mixed  $default The default value
	 *
	 * @return string The filtered value
	 */
	public function getAlnum($key, $default = '') {
		return preg_replace( '/[^[:alnum:]]/', '', $this->get( $key, $default ) );
	}
	
	/**
	 * Returns the digits of the parameter value.
	 *
	 * @param string $key     The parameter key
	 * @param mixed  $default The default value
	 *
	 * @return string The filtered value
	 */
	public function getDigits($key, $default = '') {
		return preg_replace( '/[^[:digit:]]/', '', $this->get( $key, $default ) );
	}
	
	/**
	 * Returns the parameter value converted to integer.
	 *
	 * @param string $key     The parameter key
	 * @param mixed  $default The default value
	 *
	 * @return string The filtered value
	 */
	public function getInt($key, $default = 0) {
		return ( int ) $this->get( $key, $default );
	}
}
